package jwtTool

import (
	"Gin-Server-01/com/server/core/config"
	"Gin-Server-01/com/server/core/tools/jsonTool"
	"Gin-Server-01/com/server/core/tools/yaml"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/dgrijalva/jwt-go/v4"
	"log"
	"time"
)

/**
@Title JWT(Json Web Token)的生成、刷新和解析
@CreateTime 2022年9月1日10:26:18
@Author 薛智敏
 go get github.com/dgrijalva/jwt-go/v4
*/

//
//  TokenDatas
//  @Description: 令牌
//

type TokenDatas struct {
	TokenData      any           `json:"tokenData"`      //token自定义数据
	CreateTime     time.Time     `json:"createTime"`     //创建时间
	ExpirationTime time.Duration `json:"expirationTime"` //过期时间
}

func (t *TokenDatas) JsonString() string {
	return jsonTool.JsonFormatString(t)
}

type CustomClaims struct {
	TokenDatas
	jwt.StandardClaims
}

func (c CustomClaims) JsonString() string {
	return jsonTool.JsonFormatString(c)
}

var configs *config.Config
var MySecret []byte

func init() {
	//解读yaml
	configs = yaml.ParseYAMLDefaultFileNoErr()

	MySecret = []byte(configs.JwtConfig.Secret)

}

// Encryption
//
//	@Summary:
//	@Description:  jwt
//	@Param: jwtTool_TokenDatas 加密的数据结构体
//	@Return: token 字符串jwt
func Encryption(jwtTool_TokenDatas TokenDatas) (token string) {
	token, _ = GenToken(jwtTool_TokenDatas, configs.JwtConfig.ExpireTime)

	return token
}

// Decry Decry[T any]
//
//	@Summary:
//	@Description: 泛型解密
//	@Param: tokenStr 要解密的jwt密文
//	@Param: toStruct 转换的结构体
//	@Return: T 返回解密的结构体
func Decry[T any](tokenStr string, toStruct T) T {

	token, _ := ParseToken(tokenStr)

	tokenData := jsonTool.JsonFormatString(token.TokenDatas.TokenData)
	fmt.Println(tokenData)

	err := json.Unmarshal([]byte(tokenData), &toStruct)
	if err != nil {
	}

	return toStruct
}

// RemainingTime 获取Token的剩余过期时间
//
//	@Description:
//	@receiver t
//	@return time.Duration
func (t *TokenDatas) RemainingTime() time.Duration {
	now := time.Now()
	expiration := t.CreateTime.Add(t.ExpirationTime)
	remainingTime := expiration.Sub(now)
	if remainingTime < 0 {
		return 0
	}
	return remainingTime
}

//  GenToken 创建 Token
//  @Description:
//  @param user Token携带的字段
//  @param times  过期时间
//  @return string 加密的Token
//  @return error

func GenToken(tokenDatas TokenDatas, times time.Duration) (string, error) {

	//创建时间
	tokenDatas.CreateTime = time.Now()
	//过期时间
	tokenDatas.ExpirationTime = times
	claim := CustomClaims{
		tokenDatas,

		jwt.StandardClaims{
			ExpiresAt: jwt.At(time.Now().Add(times)), //过期的时间
			Issuer:    "XueZhiMin",                   //签发人
		},
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claim)

	return token.SignedString(MySecret)
}

//  ParseToken // 解析 token
//  @Description:
//  @param tokenStr 加密的Token字段
//  @return *CustomClaims
//  @return error
//

func ParseToken(tokenStr string) (*CustomClaims, error) {
	token, err := jwt.ParseWithClaims(tokenStr, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
		return MySecret, nil
	})
	if err != nil {
		log.Println(fmt.Sprintf(" token parse err:%s", err))
		return nil, err
	}
	if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
		return claims, nil
	}
	return nil, errors.New("invalid token")
}

//
//  RefreshToken 刷新 Token
//  @Description:
//  @param tokenStr Token字段
//  @param times 重新设置的时间
//  @return string Token
//  @return error
//

func RefreshToken(tokenStr string, times time.Duration) (string, error) {
	jwt.TimeFunc = func() time.Time {
		return time.Unix(0, 0)
	}

	token, err := jwt.ParseWithClaims(tokenStr, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
		return MySecret, nil
	})
	if err != nil {
		return "", err
	}
	if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
		jwt.TimeFunc = time.Now
		claims.StandardClaims.ExpiresAt = jwt.At(time.Now().Add(times))
		return GenToken(claims.TokenDatas, times)
	}
	return "", errors.New("无法处理此令牌")
}
